package com.zbkj.service.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zbkj.dal.base.enums.ExpressOrderType;
import com.zbkj.dal.base.enums.ExpressTraceOpCode;
import com.zbkj.dal.base.enums.OrderInvoceStatus;
import com.zbkj.dal.common.exception.CrmebException;
import com.zbkj.dal.dao.ExpressTraceMapper;
import com.zbkj.dal.entity.express.ExpressTrace;
import com.zbkj.dal.entity.order.OrderInvoice;
import com.zbkj.dal.entity.order.OrderInvoiceDetail;
import com.zbkj.dal.pojo.response.OrderInvoiceResponse;
import com.zbkj.dal.dao.OrderInvoiceDao;
import com.zbkj.dal.pojo.vo.LogisticsResultVo;
import com.zbkj.service.model.dto.order.OrderInvoiceDTO;
import com.zbkj.service.service.LogisticService;
import com.zbkj.service.service.OrderInvoiceDetailService;
import com.zbkj.service.service.OrderInvoiceService;
import com.zbkj.service.sfexpress.CallExpressNewAPIService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * OrderInvoiceServiceImpl 接口实现
 * +----------------------------------------------------------------------
 * | CRMEB [ CRMEB赋能开发者，助力企业发展 ]
 * +----------------------------------------------------------------------
 * | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
 * +----------------------------------------------------------------------
 * | Licensed CRMEB并不是自由软件，未经许可不能去掉CRMEB相关版权
 * +----------------------------------------------------------------------
 * | Author: CRMEB Team <admin@crmeb.com>
 * +----------------------------------------------------------------------
 */
@Slf4j
@Service
public class OrderInvoiceServiceImpl extends ServiceImpl<OrderInvoiceDao, OrderInvoice> implements OrderInvoiceService {

    @Resource
    private OrderInvoiceDao dao;
    @Autowired
    private ExpressTraceMapper expressTraceMapper;
    @Autowired
    private OrderInvoiceDetailService orderInvoiceDetailService;
    @Autowired
    private LogisticService logisticService;
    @Autowired
    private CallExpressNewAPIService callExpressNewAPIService;

    /**
     * 获取订单发货单列表
     *
     * @param orderNo 订单号
     * @return 发货单列表
     */
    @Override
    public List<OrderInvoiceResponse> findByOrderNo(String orderNo) {
        LambdaQueryWrapper<OrderInvoice> lqw = Wrappers.lambdaQuery();
        lqw.eq(OrderInvoice::getOrderNo, orderNo);
        List<OrderInvoice> invoiceList = dao.selectList(lqw);
        if (CollUtil.isEmpty(invoiceList)) {
            return new ArrayList<>();
        }
        List<Integer> invoiceIdList = invoiceList.stream().map(OrderInvoice::getId).collect(Collectors.toList());
        List<OrderInvoiceDetail> invoiceDetailList = orderInvoiceDetailService.findInInvoiceIdList(invoiceIdList);
        return invoiceList.stream().map(invoice -> {
            OrderInvoiceResponse response = new OrderInvoiceResponse();
            BeanUtils.copyProperties(invoice, response);
            List<OrderInvoiceDetail> detailList = invoiceDetailList.stream().filter(e -> e.getInvoiceId().equals(invoice.getId())).collect(Collectors.toList());
            response.setDetailList(detailList);
            return response;
        }).collect(Collectors.toList());

    }

    @Override
    public List<LogisticsResultVo> findTraceByOrderNoAndLastTraceOnly(String orderNo) {
        LambdaQueryWrapper<OrderInvoice> lqw = Wrappers.lambdaQuery();
        lqw.eq(OrderInvoice::getOrderNo, orderNo);
        lqw.ne(OrderInvoice::getStatus, OrderInvoceStatus.CANCEL.getCode());
        List<OrderInvoice> invoiceList = dao.selectList(lqw);
        if (CollUtil.isEmpty(invoiceList)) {
            return new ArrayList<>();
        }
        return logisticService.infoListAndLastTraceOnly(invoiceList);
    }

    @Override
    public OrderInvoiceDTO findOrderInvoiceByOrderNoAndInvoiceType(String orderNo, ExpressOrderType expressOrderType) {
        LambdaQueryWrapper<OrderInvoice> lqw = Wrappers.lambdaQuery();
        lqw.eq(OrderInvoice::getOrderNo, orderNo);
        lqw.eq(OrderInvoice::getExpressOrderType, expressOrderType.name());
        OrderInvoice orderInvoice = super.getOne(lqw);
        OrderInvoiceDTO orderInvoiceDTO = new OrderInvoiceDTO();
        orderInvoiceDTO.setPickupTime(orderInvoice.getPickupTime());
        orderInvoiceDTO.setPickupCode(orderInvoice.getPickupCode());
        orderInvoiceDTO.setExpressName(orderInvoice.getExpressName());
        orderInvoiceDTO.setExpressCode(orderInvoice.getExpressCode());
        orderInvoiceDTO.setExpressOrderType(orderInvoice.getExpressOrderType());
        orderInvoiceDTO.setTrackingNumber(orderInvoice.getTrackingNumber());
        return orderInvoiceDTO;
    }

    @Override
    public OrderInvoiceResponse findOneByOrderNoAndOrderType(String orderNo, ExpressOrderType expressOrderType) {
        LambdaQueryWrapper<OrderInvoice> lqw = Wrappers.lambdaQuery();
        lqw.eq(OrderInvoice::getOrderNo, orderNo);
        lqw.eq(OrderInvoice::getExpressOrderType, expressOrderType.name());
        OrderInvoice orderInvoice = dao.selectOne(lqw);
        OrderInvoiceResponse response = new OrderInvoiceResponse();
        BeanUtils.copyProperties(orderInvoice, response);
        return response;
    }

    @Override
    public OrderInvoice findByExpressOrderNo(String expressOrderNo) {
        LambdaQueryWrapper<OrderInvoice> lqw = Wrappers.lambdaQuery();
        lqw.eq(OrderInvoice::getExpressOrderNo, expressOrderNo);
        return dao.selectOne(lqw);
    }

    @Override
    public OrderInvoice findByTrackingNumber(String trackingNumber) {
        LambdaQueryWrapper<OrderInvoice> lqw = Wrappers.lambdaQuery();
        lqw.eq(OrderInvoice::getTrackingNumber, trackingNumber);
        return dao.selectOne(lqw);
    }

    @Override
    public OrderInvoceStatus updateOrderInvoiceStatusOnExpressTraceUpdate(String trackingNumber) {
        LambdaQueryWrapper<ExpressTrace> lqw = Wrappers.lambdaQuery();
        lqw.eq(ExpressTrace::getMailNo, trackingNumber);
        lqw.orderByDesc(ExpressTrace::getId);
        lqw.last("limit 1");
        ExpressTrace expressTrace = expressTraceMapper.selectOne(lqw);
        ExpressTraceOpCode expressTraceOpCode = ExpressTraceOpCode.of(expressTrace.getOpCode());
        if (Objects.isNull(expressTraceOpCode)) {
            log.error("不支持的物流轨迹操作码, {}", trackingNumber);
            return null;
        }
        //
        LambdaQueryWrapper<OrderInvoice> invoiceLwq = Wrappers.lambdaQuery();
        invoiceLwq.eq(OrderInvoice::getTrackingNumber, trackingNumber);
        OrderInvoice orderInvoice = dao.selectOne(invoiceLwq);
        orderInvoice.setStatus(expressTraceOpCode.getCorrespondingLogisticsStatus().getCode());
        dao.updateById(orderInvoice);

        return expressTraceOpCode.getCorrespondingLogisticsStatus();
    }

    @Override
    public void cnacelExpressOrder(String platOrderNo, ExpressOrderType expressOrderType) {
        LambdaQueryWrapper<OrderInvoice> lqw = Wrappers.lambdaQuery();
        lqw.eq(OrderInvoice::getOrderNo, platOrderNo);
        lqw.eq(OrderInvoice::getExpressOrderNo, expressOrderType.name());
        lqw.last("limit 1");
        OrderInvoice orderInvoice = super.getOne(lqw);
        // 判定是否可以取消订单
        if (!Objects.equals(OrderInvoceStatus.WAITING.getCode(), orderInvoice.getStatus())) {
            throw new CrmebException("物流在途中，不可取消");
        }
        // 向顺丰取消订单
        Boolean cancelResult = callExpressNewAPIService.cancelOrder(orderInvoice.getExpressOrderNo());
        if (!cancelResult) {
            throw new CrmebException("物流取消失败");
        }
        LambdaUpdateWrapper<OrderInvoice> luw = Wrappers.lambdaUpdate();
        luw.set(OrderInvoice::getStatus, OrderInvoceStatus.CANCEL.getCode());
        luw.eq(OrderInvoice::getOrderNo, platOrderNo);
        luw.eq(OrderInvoice::getExpressOrderNo, expressOrderType.name());
        super.update(luw);
    }

    @Override
    public void updateExpressOrderPickupTime(String platOrderNo, ExpressOrderType expressOrderType, LocalDateTime pickupTime) {
        LambdaQueryWrapper<OrderInvoice> lqw = Wrappers.lambdaQuery();
        lqw.eq(OrderInvoice::getOrderNo, platOrderNo);
        lqw.eq(OrderInvoice::getExpressOrderNo, expressOrderType.name());
        lqw.last("limit 1");
        OrderInvoice orderInvoice = super.getOne(lqw);
        // 判定是否可以取消订单
        if (!Objects.equals(OrderInvoceStatus.WAITING.getCode(), orderInvoice.getStatus())) {
            throw new CrmebException("物流在途中，不可更新取件信息");
        }
        // 更新预约时间
        Boolean updateResult = callExpressNewAPIService.updateOrderPickupTime(orderInvoice.getExpressOrderNo(), orderInvoice.getTrackingNumber(), pickupTime);
        if (!updateResult) {
            throw new CrmebException("物流信息更新失败");
        }
    }
}

